﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing.Drawing2D;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;

namespace MipsPipelineSimulator
{
    public class DrawTool
    {
        private const int SRCCOPY = 0x00CC0020;

        public DrawTool()
        {

        }

        [DllImport(@"gdi32.dll")]
        public static extern int BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop);

        public void BlinkString(StringControl strControl, Point position, int times, int showSpanTime, int hideSpanTime)
        {
            strControl.Visible = false;
            strControl.Location = position;
            while (times > 0)
            {
                strControl.Show();
                Thread.Sleep(showSpanTime);
                strControl.Hide();
                Thread.Sleep(hideSpanTime);
                times--;
            }
        }

        private delegate void DrawLineDelegate(Graphics [] gs,Pen pen,int xStart,int yStart,int xEnd,int yEnd);
        static private void DrawLine(Graphics [] gs,Pen pen,int xStart,int yStart,int xEnd,int yEnd)
        {
            foreach (Graphics g in gs)
            {
                g.DrawLine(pen, xStart, yStart, xEnd, yEnd);
            }
        }

        private delegate StringControl CreateStringControlDeletgate(String text, Font font, Brush brush, Direction direction, Control control);
        static private StringControl CreateStringControl(String text, Font font, Brush brush, Direction direction,Control control)
        {
            StringControl strControl = new StringControl(text, font, brush, direction);
            control.Controls.Add(strControl);
            strControl.Location = new Point(-100, -100);
            strControl.Show();
            return strControl;
        }

        private delegate void SetStringControlLocDelegate(Point location, Control strControl);
        static private void SetStringControlLoc(Point location, Control strControl)
        {
            strControl.Location = location;
        }

        static public void Animate(Animate animateStruct, Control control)
        {
            int yStart = animateStruct.line.from.Y;
            int xStart = animateStruct.line.from.X;
            int yEnd = animateStruct.line.end.Y;
            int xEnd = animateStruct.line.end.X;
            int forward = animateStruct.forward;
            StringControl strControl = null;
            if (animateStruct.ifDisplayText)
            {
                object[] param = new object[5] { animateStruct.text, animateStruct.font, animateStruct.brush, animateStruct.direction, control};
                strControl = (StringControl)control.Invoke(new CreateStringControlDeletgate(CreateStringControl), param);
            }

            switch (animateStruct.direction)
            {
                case Direction.LeftToRight:
                    {
                        while (xStart < xEnd)
                        {
                            int temp = xStart + forward;
                            if (temp > xEnd)
                            {
                                temp = xEnd;
                            }
                            object[] param = new object[6] { animateStruct.g, animateStruct.line.pen,xStart,yStart,temp,yEnd};
                            control.BeginInvoke(new DrawLineDelegate(DrawLine),param);
                            if (animateStruct.ifDisplayText)
                            {
                                object[] param1 = new object[2] { new Point(temp, yEnd + 400), strControl };
                                control.BeginInvoke(new SetStringControlLocDelegate(SetStringControlLoc), param1);
                            }
                            xStart = temp;
                            Thread.Sleep(animateStruct.spanTime);
                        }
                        break;
                    }
                case Direction.TopToBottom:
                    {
                        while (yStart < yEnd)
                        {
                            int temp = yStart + forward;
                            if (temp > yEnd)
                            {
                                temp = xEnd;
                            }
                            object[] param = new object[6] { animateStruct.g, animateStruct.line.pen, xStart, yStart, xEnd, temp };
                            control.BeginInvoke(new DrawLineDelegate(DrawLine), param);
                            yStart = temp;
                            Thread.Sleep(animateStruct.spanTime);
                        }
                        break;
                    }
                case Direction.RightToLeft:
                    {
                        while (xStart > xEnd)
                        {
                            int temp = xStart - forward;
                            if (temp < xEnd)
                            {
                                temp = xEnd;
                            }
                            object[] param = new object[6] { animateStruct.g, animateStruct.line.pen, temp, yStart, xStart, yEnd };
                            control.BeginInvoke(new DrawLineDelegate(DrawLine), param);
                            xStart = temp;
                            Thread.Sleep(animateStruct.spanTime);
                        }
                        break;
                    }
                case Direction.BottomToTop:
                    {
                        while (yStart > yEnd)
                        {
                            int temp = yStart - forward;
                            if (temp < yEnd)
                            {
                                temp = xEnd;
                            }
                            object[] param = new object[6] { animateStruct.g, animateStruct.line.pen, xStart, temp, xEnd, yStart };
                            control.BeginInvoke(new DrawLineDelegate(DrawLine), param);
                            yStart = temp;
                            Thread.Sleep(animateStruct.spanTime);
                        }
                        break;
                    }
            }
        }

        static public void DrawPath(Graphics[] graphics, Point[] points, Pen pen)
        {
            foreach (Graphics g in graphics)
            {
                g.DrawLines(pen, points);
            }
        }

        static public void DrawPaths(Animate [] animates, Control control)
        {
            foreach (Animate animate in animates)
            {
                DrawTool.Animate(animate,control);
            }
        }
    }
}
